//! @Author: DengLibin
//! @Date: Create in 2024-01-22 14:31:57
//! @Description: 导出公钥

#[cfg(windows)]
extern crate winapi;

use winapi::um::errhandlingapi::GetLastError;
use winapi::um::winbase::FormatMessageW;
use winapi::um::winbase::FORMAT_MESSAGE_ALLOCATE_BUFFER;
use winapi::um::winbase::FORMAT_MESSAGE_FROM_SYSTEM;
use winapi::um::winbase::FORMAT_MESSAGE_IGNORE_INSERTS;
use winapi::um::winbase::FORMAT_MESSAGE_MAX_WIDTH_MASK;
use winapi::um::wincrypt::CryptAcquireContextA;

use winapi::um::wincrypt::CryptReleaseContext;

use winapi::um::wincrypt::HCRYPTPROV;

use winapi::shared::minwindef::BOOL;

use winapi::um::winnt::LANG_NEUTRAL;

use winapi::um::winnt::MAKELANGID;
use winapi::um::winnt::SUBLANG_DEFAULT;

use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::ptr;
use std::ptr::null_mut;

use rust_common::base64;
use winapi::shared::winerror::{
    ERROR_BUSY, ERROR_NOT_ENOUGH_MEMORY, NTE_BAD_FLAGS, NTE_BAD_KEYSET, NTE_KEYSET_ENTRY_BAD,
    NTE_KEYSET_NOT_DEF, NTE_NO_MEMORY, NTE_PROV_DLL_NOT_FOUND,
};

use winapi::um::wincrypt::PROV_RSA_FULL;
// CSP(加密服务提供商名称)
const PROVIDER_NAME: &str = "EnterSafe ePass3000GM CSP v1.0";

// usbkey中密钥容器名称
const CONTAINER: &str = "yiscn";

/// @Author: DengLibin
/// @Date: Create in 2024-01-18 11:12:43
/// @Description: rsa加解密
#[cfg(windows)]
pub fn export() {
    use winapi::{
        shared::minwindef::DWORD,
        um::{
            ncrypt::HCRYPTKEY,
            wincrypt::{
                CryptDestroyKey, CryptExportKey, CryptGetUserKey, AT_KEYEXCHANGE, PUBLICKEYBLOB
            },
        },
    };

    let mut sz_provider = PROVIDER_NAME.as_bytes().to_vec();
    //加一个0结尾
    sz_provider.push(0);

    //转i8
    let provider_str = sz_provider
        .iter()
        .map(|item| *item as i8)
        .collect::<Vec<i8>>();
    //转指针
    let provider = provider_str.as_ptr();
    //清理
    drop(sz_provider);

    let mut sz_container = CONTAINER.as_bytes().to_vec();
    //加一个0结尾
    sz_container.push(0);

    //转i8
    let sz_container_str = sz_container
        .iter()
        .map(|item| *item as i8)
        .collect::<Vec<i8>>();
    // 转指针
    let sz_container_p = sz_container_str.as_ptr();
    //清理
    drop(sz_container);

    unsafe {
        // 定义加密上下文句柄
        let mut hprov: HCRYPTPROV = 0;
        let hp = &mut hprov;
        //获取上下文句柄
        let b: BOOL = CryptAcquireContextA(hp, sz_container_p, provider, PROV_RSA_FULL, 0);
        println!("初始化上下文结果：{},句柄:{}", b, *hp);

        let success: bool = b != 0;
        if !success {
            let error_code = GetLastError();
            if error_code as i32 == NTE_BAD_KEYSET {
                println!("无法打开密钥容器或容器不存在");
            } else if error_code == ERROR_NOT_ENOUGH_MEMORY {
                println!("操作系统在操作期间内存不足");
            } else if error_code == ERROR_BUSY {
                println!("另一个线程或进程正在使用此密钥容器");
            } else if error_code as i32 == NTE_KEYSET_ENTRY_BAD {
                println!("找到 pszContainer 密钥容器，但已损坏");
            } else if error_code as i32 == NTE_KEYSET_NOT_DEF {
                println!("请求的提供程序不存在。");
            } else if error_code as i32 == NTE_NO_MEMORY {
                println!("CSP 在操作期间内存不足。");
            } else if error_code as i32 == NTE_PROV_DLL_NOT_FOUND {
                println!("提供程序 DLL 文件不存在或不在当前路径上。");
            } else if error_code as i32 == NTE_BAD_FLAGS {
                println!("dwFlags 参数的值无效。");
            } else
            //容器已存在
            if error_code == 0x8009000F {
                println!("容器已存在:{}", CONTAINER);
            }
        }

        // 成功
        if success {
            //获取加密key
            let mut h_key: HCRYPTKEY = 0;

            if CryptGetUserKey(hprov, AT_KEYEXCHANGE, &mut h_key) == 0 {
                println!("获取加密key错误");
                show_error();
            } else {
                println!("获取加密key成功:{}", h_key);
            }

            //第一次导出密钥，获取长度
            let mut dw_blob_len: DWORD = 0;
            //密钥缓冲区
            let mut key_buf = vec![];

            if CryptExportKey(h_key, 0, PUBLICKEYBLOB, 0, null_mut(), &mut dw_blob_len) == 0
            //public key blob length
            {
                println!("第一次导出密钥失败");
                show_error();
            } else {
                println!("第一次导出密钥成功,长度:{}", dw_blob_len);
                //根据长度创建缓冲区
                key_buf = vec![0; dw_blob_len as usize];
                if CryptExportKey(
                    h_key,
                    0,
                    PUBLICKEYBLOB,
                    0,
                    key_buf.as_mut_ptr(),
                    &mut dw_blob_len,
                ) == 0
                {
                    println!("第二次导出密钥失败");
                    show_error();
                } else {
                    println!("第二次导出密钥成功,长度:{}", dw_blob_len);
                 
                    println!("第二次导出密钥成功:{}", base64::encode_bytes(&key_buf[..dw_blob_len as usize]));
                    for i in key_buf {
                        print!("{:X}, ", i);
                    }
                }
            }

            CryptDestroyKey(h_key);

            let b: BOOL = CryptReleaseContext(hprov, 0);
            println!("释放结果:{}", b);
        } else {
            println!("获取上下文句柄错误");
            show_error();
        }
    }
}

#[allow(dead_code)]
fn show_error() {
    let error_code = 123; // 假设这是一个错误代码
    let mut buffer = [0; 256]; // 分配一个足够大的缓冲区
    let buffer_ptr: *mut u16 = buffer.as_mut_ptr();

    let flags = FORMAT_MESSAGE_ALLOCATE_BUFFER
        | FORMAT_MESSAGE_FROM_SYSTEM
        | FORMAT_MESSAGE_IGNORE_INSERTS
        | FORMAT_MESSAGE_MAX_WIDTH_MASK;
    let result = unsafe {
        FormatMessageW(
            flags,
            ptr::null(),
            error_code,
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) as u32,
            buffer_ptr,
            256,
            ptr::null_mut(),
        )
    };

    if result == 0 {
        // 如果FormatMessageA失败，获取错误代码
        let last_error = unsafe { winapi::um::errhandlingapi::GetLastError() };
        eprintln!("FormatMessageA failed with error code: {}", last_error);
    } else {
        // 成功获取消息，打印出来
        let wide_message = unsafe {
            // 将宽字符指针转换为OsString
            OsString::from_wide(&buffer)
        };
        let message = wide_message.to_string_lossy().into_owned();
        println!("Message: {}", message);
    }
}
